<?php
namespace Hphp\Pipeline;

use Hphp\Foundation\Application;

class Pipeline
{
    /**
     * @var \Hphp\Foundation\Application
     */
    protected $app;

    /**
     * 设置request或者其他需要的参数
     *
     * @var mixed
     */
    protected $passable;
    /**
     * 定义中间件的执行方法
     *
     * @var string
     */
    protected $method = 'handle';

    protected $pipes = [];

    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    /**
     * 启动管道的方法
     */
    public function then(\Closure $desctination)
    {
        $pipeline = array_reduce(
            $this->pipes(),
            $this->carry(),
            $desctination
        );
        return $pipeline($this->passable);
    }

    /**
     * 设置中间件
     */
    public function through($pipes)
    {
        $this->pipes = is_array($pipes) ? $pipes : func_get_args();

        return $this;
    }

    /**
     * 中间件链表
     */
    public function pipes()
    {
        return $this->pipes;
    }

    /**
     * 管道执行方法
     */
    public function carry()
    {
        return function ($stack, $pipe) {
            return function ($passable) use ($stack, $pipe) {
                try {
                    if (is_callable($pipe)) {
                        return $pipe($passable, $stack);
                    } elseif (! is_object($pipe)) {
                        $pipe = $this->app->make($pipe);
                        $parameters = [$passable, $stack];
                    }

                    return  method_exists($pipe, $this->method)
                        ? $pipe->{$this->method}(...$parameters)
                        : $pipe(...$parameters);

                } catch (Throwable $e) {
                }
            };
        };

        // return function($stack, $pipe){
        //     return function() use ($stack, $pipe){
        //         // return $pipe::hander($stack);
        //         // echo $pipe."<br>";
        //     };
        // };
    }

    /**
     * 管道中需要的某一些参数
     */
    public function send($passable)
    {
        $this->passable = $passable;

        return $this;
    }
}